package SintaticoPacote;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */


import SintaticoPacote.TratamentoErro.ErroTabela;
import SintaticoPacote.TratamentoErro.TabelaErros;
import compilador_full.TabelaSimbolos;

/**
 *
 * @author Jomas
 */
public class ExpAtribuicao {

    // expressão atribuição
    // <expAtribuicao> ::=  * <nome> ( = <termoAtribuicao> |  ++ | - - ) ; |
    // <nome> ( = <termoAtribuicao2> |  ++ | - - | <acessoStruct> ) ;
    public boolean  expatribuicao (TabelaSimbolos tabelasimbolos) {

        // verifica se é * <nome>
        if (tabelasimbolos.getLookahead().equals("*")) {
            //  se for é porque é do tipo
            //  * <nome> ( = <termoAtribuicao> |  ++ | - - ) ;
            //
            // Consome o simbolo *
            tabelasimbolos.reconhecer("*");
            // verifica se é um identificador
            if (tabelasimbolos.getTipo().equals("identificador")) {
                // se for um identificador é da forma
                //  * <nome>
                // apenas consome o nome <nome>
                tabelasimbolos.soConsome();
                //
                // verifica se é um ;
                 if (tabelasimbolos.getLookahead().equals(";")) {
                    // se for logo é da forma
                    // Consome o simbolo ;
                    tabelasimbolos.reconhecer(";");
                    // logo é da forma errada * <nome> ;
                    return false;
                 // verufica se é um =
                 } else if (tabelasimbolos.getLookahead().equals("=")) {
                     // daí seria da forma
                     // * <nome> = <termoAtribuicao>
                     // logo reconhece =
                     tabelasimbolos.reconhecer("=");
                     // chama o método para termoAtribuicao
                     // metodo abaixo       "public boolean termoAtribuicao (TabelaSimbolos tabelasimbolos)"
                     if (termoAtribuicao(tabelasimbolos)) {
                        // logo seria da forma
                        // * <nome> = <termoAtribuicao>
                        // verifica se o proximo é um ;
                        if (tabelasimbolos.getLookahead().equals(";")) {
                            // se for é da forma
                            // * <nome> = <termoAtribuicao> ;
                            // Consome o simbolo ;
                            tabelasimbolos.reconhecer(";");
                            // retorna verdadeiro
                            return true;
                        // não encontrou um ;
                        } else {
                            // logo é erro retorna false ERRO
                            ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                            TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                            return false; //se nao achar }
                        }
                     // se termoAtribuicao retornar false é porque teve erro em seu nivel - isto é não encontrou um <termoAtribuicao> correto
                     } else {
                        // se não é um erro
                        ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                        TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                        return false; //se nao achar }
                     }
                 // verufica se é um ++ ou se é um --
                 } else if (tabelasimbolos.getLookahead().equals("++") || tabelasimbolos.getLookahead().equals("--")) {
                    // se for então é da forma
                    //  * <nome> ++ ou da forma * <nome> --
                    // logo apenas reconhece o ++ ou --
                    tabelasimbolos.soConsome();
                    // verifica se o proximo é um ;
                    if (tabelasimbolos.getLookahead().equals(";")) {
                        // se for é da forma
                        // <nome> ++ ; ou da forma <nome> -- ;
                        // Consome o simbolo ;
                        tabelasimbolos.reconhecer(";");
                        // retorna verdadeiro
                        return true;
                    // aqui é um erro caso não encontre ;
                    } else {
                        // logo é erro retorna false ERRO
                        ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                        TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                        return false; //se nao achar }
                    }
                 // nesse ponto verifica se encontrou um <nome> mas depois não encontrou um  = <termoAtribuicao> ou  ++ ou -- ou ;
                 } else {
                    // se não é um erro
                    ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                    TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                    return false; //se nao achar }
                 }
            // esse erro é para caso de depois de um * não vim o nome
            } else {
                // se não é um erro
                ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                return false; //se nao achar }
            }
        //
        // <nome> ( = <termoAtribuicao2> |  ++ | - - | <acessoStruct> ) ;
        } else {
            // se não for é porque é do tipo
            // <nome> ( = <termoAtribuicao2> |  ++ | - - | <acessoStruct> ) ;
            //
            // verifica se é um identificador
            if (tabelasimbolos.getTipo().equals("identificador")) {
                // se for um identificador é da forma
                //  * <nome>
                // apenas consome o nome <nome>
                tabelasimbolos.soConsome();

                if(tabelasimbolos.getLookahead().equals("[")) {
                    while(tabelasimbolos.getLookahead().equals("[")) {
                        if(tabelasimbolos.reconhecer("[")) {
                            if(tabelasimbolos.getTipo().equals("identificador") ||
                               tabelasimbolos.getTipo().equals("numero")) {
                                tabelasimbolos.soConsome();
                                if(!tabelasimbolos.reconhecer("]"))
                                    return false;
                            }
                            else {
                                ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                                TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                                return false; //se nao achar }
                            }
                        }
                        else return false;
                    }
                }

                if(tabelasimbolos.getLookahead().equals("->") ||
                        tabelasimbolos.getLookahead().equals(".")) {
                    tabelasimbolos.soConsome();
                    if(tabelasimbolos.getTipo().equals("identificador")) {
                        tabelasimbolos.soConsome();
                    }
                    else {
                        ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                        TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                        return false; //se nao achar }
                    }

                }
                //
                // verifica se é um ;
                 if (tabelasimbolos.getLookahead().equals(";")) {
                    // se for logo é da forma
                    // Consome o simbolo ;
                    tabelasimbolos.reconhecer(";");
                    // logo é da forma errada  <nome> ;
                    return false;
                 // verufica se é um =
                 } 
                 else if (tabelasimbolos.getLookahead().equals("=")) {
                     // daí seria da forma
                     // <nome> = <termoAtribuicao2>
                     // logo reconhece =
                     tabelasimbolos.reconhecer("=");
                     // chama o método para termoAtribuicao
                     // metodo abaixo       "public boolean termoAtribuicao (TabelaSimbolos tabelasimbolos)"
                     if (termoAtribuicao2(tabelasimbolos)) {
                        // logo seria da forma
                        // <nome> = <termoAtribuicao2>
                        // verifica se o proximo é um ;
                        if (tabelasimbolos.getLookahead().equals(";")) {
                            // se for é da forma
                            // <nome> = <termoAtribuicao2> ;
                            // Consome o simbolo ;
                            tabelasimbolos.reconhecer(";");
                            // retorna verdadeiro
                            return true;
                        // não encontrou um ;
                        } else {
                            // logo é erro retorna false ERRO
                            ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                            TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                            return false; //se nao achar }
                        }
                     // se termoAtribuicao retornar false é porque teve erro em seu nivel - isto é não encontrou um <termoAtribuicao2> correto
                     } else {
                        // se não é um erro
                        return false;
                     }
                 // verufica se é um ++ ou se é um --
                 } else if (tabelasimbolos.getLookahead().equals("++") || tabelasimbolos.getLookahead().equals("--")) {
                    // se for então é da forma
                    //  <nome> = <termoAtribuicao2> ++ ou da forma * <nome> = <termoAtribuicao2> --
                    // logo apenas reconhece o ++ ou --
                    tabelasimbolos.soConsome();
                    // verifica se o proximo é um ;
                    if (tabelasimbolos.getLookahead().equals(";")) {
                        // se for é da forma
                        // * <nome> = <termoAtribuicao> ;
                        // Consome o simbolo ;
                        tabelasimbolos.reconhecer(";");
                        // retorna verdadeiro
                        return true;
                    // aqui é um erro caso não encontre ;
                    } else {
                        // logo é erro retorna false ERRO
                        ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                        TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                        return false; //se nao achar }
                    }
                    //
                 // verufica se é um -> ou um .
                 } else if (tabelasimbolos.getLookahead().equals("->") || tabelasimbolos.getLookahead().equals(".")) {
                    // se for é do tipo
                    // <nome> <acessoStruct>  isto é nome->nome ou nome.nome
                    // logo so consome -> ou .
                    tabelasimbolos.soConsome();
                    // cria o obejto struct
                    acessoStruct acessoStr = new acessoStruct();
                    // daí vai para o método acessoStruct
                    if (acessoStr.acessoStruct(tabelasimbolos)) {
                        // se for verdadeiro
                        // verifica se o proximo é um ;
                        if (tabelasimbolos.getLookahead().equals(";")) {
                            // se for é da forma
                            // * <nome> = <termoAtribuicao> ;
                            // Consome o simbolo ;
                            tabelasimbolos.reconhecer(";");
                            // retorna verdadeiro
                            return true;
                        // aqui é um erro caso não encontre ;
                        } else {
                            // logo é erro retorna false ERRO
                            ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                            TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                            return false; //se nao achar }
                        }
                        //
                    // se não é um erro de acessoStruct isto é acessoStruct mal formado
                    } else {
                        // logo é erro retorna false ERRO
                        return false;
                    }
                 // nesse ponto verifica se encontrou um <nome> mas depois não encontrou um  = <termoAtribuicao> ou  ++ ou -- ou ;
                 } else {
                    // se não é um erro
                    ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                    TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                    return false; //se nao achar }
                 }
            //
            // esse erro é para caso de depois de um * não vim o nome
            } else {
                // se não é um erro
                ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
                TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
                return false; //se nao achar }
            }
            //
        }
      //
    }

    // Metodo termoAtribuição
    public boolean termoAtribuicao (TabelaSimbolos tabelasimbolos) {

        // verifica a indesisão pois, <nome>, chamada de função, expressão começam com o mesmo simbolo
        // <termoAtribuicao> ::= <nome> | <numero> | <chamadaDeFuncao> | <expAritmetica> | <boolean> | “<caracter>” )
        if (tabelasimbolos.getTipo().equals("identificador") && tabelasimbolos.superTipo(1).equals("(")) {
            // se for será chamada de função
            // nome ( )
            chamadaDeFuncao chamada = new chamadaDeFuncao(tabelasimbolos);
            if(chamada.chamaFuncao())
            {
                return true;
            }
            else
            {
                return false;
            }
            //**


        // verifica se é uma expressão aritmetica
        } else if ((tabelasimbolos.getTipo().equals("identificador") || tabelasimbolos.getTipo().equals("numero")) && tabelasimbolos.superTipo(1).equals("operador")) {
            // se for será expressão aritmetica
            // <expAritmetica> ou seja a + b ou 1 + a
            if(ExpressaoAritmetica.expAritmetica(tabelasimbolos))
            {
                return true;
            }
            else
            {
                return false;
            }
            //**

        // vericia se é somente um nome
        } else if (tabelasimbolos.getTipo().equals("identificador")) {
            // se for um identificador é do tipo
            // <nome> ou do tipo identificador
            // então somente consome
            tabelasimbolos.soConsome();
            // retorna para o metodo que o invocou
            return true;

        // vericia se é somente um numero
        } else if (tabelasimbolos.getTipo().equals("numero")) {
            // se for um numero é do tipo
            // <numero>
            // então somente consome
            tabelasimbolos.soConsome();
            // retorna para o metodo que o invocou
            return true;

        // vericia se é somente um boolean
        } else if (tabelasimbolos.getLookahead().equals("true") || tabelasimbolos.getLookahead().equals("false")) {
            // se for um boolean é do tipo
            // <boolean> isto é true ou false
            // então somente consome
            tabelasimbolos.soConsome();
            // retorna para o metodo que o invocou
            return true;

        // vericfica se é um caracter isto é se é do tipo frase e o tamanho é igual a 3 ou seja "a" tamanho igual a 3
        } else if (tabelasimbolos.getTipo().equals("frase") && tabelasimbolos.getLookahead().length() == 3) {
            // se for uma frase com tres de tamanho, logo um caracter
            // "a" é um caracter
            // então somente consome
            tabelasimbolos.soConsome();
            // retorna para o metodo que o invocou
            return true;
            //
        }
       // para os outros casos retorna False
       // retorna falso;
       return false;
     //
    }
    //
    // Metodo termoAtribuição 2
    public boolean termoAtribuicao2 (TabelaSimbolos tabelasimbolos) {

        // <termoAtribuicao> ::= <nome> | <numero> | <chamadaDeFuncao> | <expAritmetica> | <boolean> | “<caracter>” )
        // se for & logo será um & <nome>
        if (tabelasimbolos.getLookahead().equals("&")) {
            // então será da forma & nome
            // daí so consome o &
            tabelasimbolos.soConsome();
            // verifica se depois vem um nome
            if (tabelasimbolos.getTipo().equals("identificador")) {
                // se sim recohece o nome = identificador
                // e consome o nome
                tabelasimbolos.soConsome();
                // retornando true
                return true;
            // se não vier um nome
            } else {
                // retornará ERRo
                return false;
            }
        // verifica a indesisão pois, <nome>, chamada de função, expressão começam com o mesmo simbolo
        // se depois de um nome vier um ( logo será chamada de função
        } else if (tabelasimbolos.getTipo().equals("identificador") && tabelasimbolos.superLookahead(1).equals("(")) {
            // se for será chamada de função
            // nome ( )
            chamadaDeFuncao chamada = new chamadaDeFuncao(tabelasimbolos);
            if(chamada.chamaFuncao())
            {
                return true;
            }
            else
            {
                return false;
            }
            //**

        // verifica se é uma expressão aritmetica
        } else if ((tabelasimbolos.getTipo().equals("identificador") || tabelasimbolos.getTipo().equals("numero")) && tabelasimbolos.superTipo(1).equals("operador")) {
            // se for será expressão aritmetica
            // <expAritmetica> ou seja a + b ou 1 + a

            if(ExpressaoAritmetica.expAritmetica(tabelasimbolos))
            {
                return true;
            }
            else
            {
                return false;
            }
            //**

        // vericia se é somente um nome
        } else if (tabelasimbolos.getTipo().equals("identificador")) {
            // se for um identificador é do tipo
            // <nome> ou do tipo identificador
            // então somente consome
            tabelasimbolos.soConsome();
            // retorna para o metodo que o invocou
            return true;

        // vericia se é somente um numero
        } else if (tabelasimbolos.getTipo().equals("numero")) {
            // se for um numero é do tipo
            // <numero>
            // então somente consome
            tabelasimbolos.soConsome();
            // retorna para o metodo que o invocou
            return true;

        // vericia se é somente um boolean
        } else if (tabelasimbolos.getLookahead().equals("true") || tabelasimbolos.getLookahead().equals("false")) {
            // se for um boolean é do tipo
            // <boolean> isto é true ou false
            // então somente consome
            tabelasimbolos.soConsome();
            // retorna para o metodo que o invocou
            return true;

        // vericfica se é um caracter isto é se é do tipo frase e o tamanho é igual a 3 ou seja "a" tamanho igual a 3
        } else if (tabelasimbolos.getTipo().equals("frase") && tabelasimbolos.getLookahead().length() == 3) {
            // se for uma frase com tres de tamanho, logo um caracter
            // "a" é um caracter
            // então somente consome
            tabelasimbolos.soConsome();
            // retorna para o metodo que o invocou
            return true;
            //
        // vericfica se é um caracter isto é se é do tipo frase isto é tamanho maior que 3
        } else if (tabelasimbolos.getTipo().equals("frase") && tabelasimbolos.getLookahead().length() > 3) {
            // se for uma frase, tamanho maior que 3
            // "frase" é um frase
            // então somente consome
            tabelasimbolos.soConsome();
            // retorna para o metodo que o invocou
            return true;
            //
        }
       // para os outros casos retorna False
       // retorna falso;
       ErroTabela erro = new ErroTabela(tabelasimbolos.getLinha(), "Erro na linha " + tabelasimbolos.getLinha());
       TabelaErros.getInstance().getTabelaErros().add(erro);// Tabela de Erros ja contem o erro. Isso que será impresso na tela.
       return false; //se nao achar }
     //

    }

}